module Fluxr::Controllers
  
  class Test < R '/test'
    def get
      @workflows = @@engine.list_workflows
      render :test, :HTML
    end
  end
  
  # Resource representing a workflow instance.
  class Workflows < REST 'workflows'
    
    def create
      workflow_def = @input[:workflow_definition]
      begin
        uri_or_class = URI.parse(workflow_def)
      rescue URI::InvalidURIError
        if Object.const_defined?(workflow_def) or const_defined?(workflow_def)
          uri_or_class = workflow_def.constantize
        else
          @message = "'#{workflow_def}' does not refer to a workflow definition."
          return render_error
        end
      end
      
      li = OpenWFE::LaunchItem.new(uri_or_class)
      
      if @input[:data]
        @input[:data].each do |k,v|
          li.send("#{k}=", v)
        end
      end
      
      li.item_type = "New Project"
      li.requester_username = "mzukowski"
      li.manager_username = "mzukowski"
      li.manager_approval_instructions = "Test test test"
      
      begin
        @fei = @@engine.launch(li)
        render :workflow_create
      rescue OpenWFE::ParameterException => e
        @message = "The initial data payload does not meet the requirements for this workflow: #{e}"
        render_error
      end
    end
    
    # Status of a workflow instance.
    # id :: The workflow instance ID (wfid) of the workflow in question.
    def read(id)
      @wfid = id
      @s = @@engine.get_process_status(@wfid)[id]
      
      if @s
        render :workflow_status
      else
        @message = "Invalid workflow id!"
        render_error
      end
    end
    
    # Update the workitem data held by a participant in a workflow instance.
    # id :: The workflow instance ID (wfid) of the workflow in question.
    #
    # Parameters:
    # participant :: The name of the participant to update. Must refer to an
    #                active participant -- that is, a participant waiting
    #                for an update.
    # data ::        A hash with the replacement data for the workitem held by 
    #                the participant.
    def update(id)
      @wfid = id
      
      unless participant_name = @input[:participant]
        @message = "A participant name must be specified."
        return render_error
      end
      
      participant = @@engine.get_participant(participant_name)
      
      unless participant
        @message = "There is no participant '#{participant_name}' registered with the workflow engine."
        return render_error
      end
      
      # Get the list of all participants waiting for an update
      if state = @@engine.get_process_status(@wfid)[id]
        participant_expression = state.expressions.find do |exp| 
          exp.kind_of?(OpenWFE::ParticipantExpression) && 
            exp.participant_name == participant_name
        end
      end
      
      # If we found some waiting participants, check if the one we're looking for
      # is among them, and try to update its attributes and resume the workflow.
      if participant_expression
        @workitem = participant[participant_expression.fei]
        data = @input[:data]
        data.each do |k,v|
          @workitem.attributes[k] = v
        end
        participant.proceed(@workitem)
        render :workflow_update
      else
        @message = "The participant '#{participant_name}' is not currently active within workflow '#{@wfid}'!"
        render_error
      end
    end
    
    # Kill a workflow instance.
    def destroy(id)
      @@engine.cancel_process(id)
      render :workflow_destroy
    end
    
    # List of workflow instances along with their statuses.
    def list
      @ss = @@engine.get_process_status
      
      render :workflow_list
    end
    
    private
      # Renders an error response. Uses the contents of @message as the error message.
      def render_error
        @status = 500
        render :error
      end
  end
  
  
  class WorkflowDefinitions < REST 'workflow_definitions'
    # not yet implemented...
  end
  
  class Participants < REST 'participants'
    # List of participants registered with the engine.
    def list
      @participant_map = @@engine.get_participant_map
      render :participant_list
    end
  end
  
  class ParticipantDefinitions < REST 'participant_definitions'
    # List of participant definitions that the server is able to register.
    def list
      @participant_map = @@engine.get_participant_map
      render :participant_list
    end
  end
end